#include "transfer.h"

#define TRANSFER_BUFF_LEN 64 * 1024

int transfer_conn2c(int16_t cmd, int32_t flag, connev_t* connev)
{
	if(!connev) return -1;
	struct conn_head_t client_head;
	client_head.cmd = cmd;
	client_head.flag = flag;
	client_head.pkg_crc = 0;
	client_head.pkg_len = 0;
	char serialbuf[sizeof(client_head)];
	size_t buflen = sizeof(client_head);
	int ret = serialize_conn_head(&client_head, serialbuf, &buflen);
	assert(0 == ret);
	
	ret = connev_write(connev, serialbuf, buflen);	
	if(0 == ret)
	{
		LOG_TRACE("connev from %s send:  cmd=%d flag=%d", 
			connev_peer_addr(connev), cmd, flag);
	}
	else
	{
		LOG_ERROR("connev from %s send fail:  cmd=%d flag=%d", 
			connev_peer_addr(connev), cmd, flag);
	}
	return ret;
}

int transfer_conn2c_pkg(int16_t cmd,int32_t flag, const char* pkgbuf, 
		size_t pkgbuflen, int32_t encrypt_key, connev_t* connev)
{
	if(!connev || !pkgbuf) return -1;
	struct conn_head_t client_head;
	client_head.cmd = cmd;
	client_head.flag = flag;
	client_head.pkg_crc = 0;
	client_head.pkg_len = 0;
	
	static char serialbuf[TRANSFER_BUFF_LEN];
	int ret;

	char* serialize_pkgbuf = serialbuf + sizeof(client_head);
	size_t serialize_pkgbuflen = TRANSFER_BUFF_LEN - sizeof(client_head);
	ret = base_encrypt(pkgbuf, pkgbuflen, encrypt_key, serialize_pkgbuf, &serialize_pkgbuflen);
	assert(0 == ret);

	client_head.pkg_len = serialize_pkgbuflen;
	client_head.pkg_crc = crc32(serialize_pkgbuf, serialize_pkgbuflen);
	size_t conn_buflen = sizeof(client_head);
	ret = serialize_conn_head(&client_head, serialbuf, &conn_buflen);
	assert(0 == ret && conn_buflen == sizeof(client_head));
	
	ret = connev_write(connev, serialbuf, conn_buflen + serialize_pkgbuflen);
	if(0 == ret)
	{
		LOG_TRACE("connev from %s send:  encrypt pkg len=%d", 
			connev_peer_addr(connev), serialize_pkgbuflen);
	}
	else
	{
		LOG_ERROR("connev from %s send fail: encrypt pkg len=%d", 
			connev_peer_addr(connev), serialize_pkgbuflen);
	}
	return ret;
}

#define CONN2S_HEAD_TIMESTAMP(stamp) \
	do {\
		struct timeval now; \
		event_base_gettimeofday_cached(gCtx->reactor, &now); \
		stamp = ((uint64_t)now.tv_sec << 32) | ((uint64_t)now.tv_usec); \
	}while(0)

int transfer_conn2s(int16_t cmd, int32_t address, struct LSI* lsi, lsi_ip_t server_addr)
{
	struct server_head_t server_head;
	server_head.cmd = cmd;
	server_head.address = address;
	server_head.pkg_len = 0;
	server_head.pkg_crc = 0;
	CONN2S_HEAD_TIMESTAMP(server_head.timestamp);

	char serialbuf[sizeof(server_head)];
	size_t serialbuflen = sizeof(server_head);
	int ret;
	ret = 	serialize_server_head(&server_head, serialbuf, &serialbuflen);
	assert(0 == ret && serialbuflen == sizeof(server_head));
	
	ret = lsi_send(lsi, server_addr, serialbuf, serialbuflen);
	if(ret == 0)
	{
		LOG_TRACE("LSI(%d) write: cmd=%d", address, cmd);
	}
	else
	{
		LOG_ERROR("LSI(%d) write fail: cmd=%d  ret=%d", address, cmd, ret);
	}
	return ret;
}

int transfer_conn2s_pkg(int16_t cmd, int32_t address, const char* pkgbuf, 
				size_t pkgbuf_len, int32_t encrypt_key, struct LSI* lsi, lsi_ip_t server_addr)
{
	if(!pkgbuf || !lsi) return -1;

	struct server_head_t server_head;
	server_head.cmd = cmd;
	server_head.address = address;
	CONN2S_HEAD_TIMESTAMP(server_head.timestamp);

	int ret;
	static char serialbuf[TRANSFER_BUFF_LEN];

	/* descrypt */
	char* desbuf = serialbuf + sizeof(server_head);
	size_t desbuf_len = TRANSFER_BUFF_LEN - sizeof(server_head);
	ret = base_descrypt(pkgbuf, pkgbuf_len, encrypt_key, desbuf, &desbuf_len);
	assert(0 == ret);

	server_head.pkg_len = desbuf_len;
	server_head.pkg_crc = crc32(desbuf, desbuf_len);

	/* server head */
	size_t headbuf_ken = sizeof(server_head);
	ret = serialize_server_head(&server_head, serialbuf, &headbuf_ken);
	assert(0 == ret && headbuf_ken == sizeof(server_head));

	/* send */
	ret = lsi_send(gCtx->lsi, gCtx->cfg->lsi_server_ip, serialbuf, headbuf_ken + desbuf_len);
	if(0 == ret)
	{
		LOG_TRACE("LSI(%d) write: pkg len=%d", address, desbuf_len);
	}
	else
	{
		LOG_ERROR("LSI(%d) write fail: pkg len=%d, ret=%d", address, desbuf_len, ret);
	}
	return ret;
}

